#include <Game.h>

PlayerCharacter::PlayerCharacter()
{
	//
	mKeystrokes = new list<Keystroke_t*>();
	mLastMatchedBeatObject = 0;
	mMultiplier = 1.0;
	mPerformedCommand = NULL;
	mTimeUntilIdle = 0.0;
}

PlayerCharacter::~PlayerCharacter()
{
	//
	
	delete mKeystrokes;
}

void PlayerCharacter::update(float timeSinceStart)
{
	//Base case
	if(mLastTime == 0)
	{
		mLastTime = timeSinceStart;
		return;
	}
	
	float delta = timeSinceStart - mLastTime;
	mLastTime = timeSinceStart;
	
	if(mIsAttacking)
	{
		mTimeUntilIdle -= delta;
		
		if(mTimeUntilIdle <= 0.0)
		{
			//Reset attack state to not attacking
			mIsAttacking = false;
			mTimeUntilIdle = 0;
			mPerformedCommand->statePtr = false;
			mPerformedCommand = NULL;
		}
	}
	
	
}

void PlayerCharacter::pressed(char ch, unsigned int timestamp)
{
	//Create keystroke
	Keystroke_t* k = (Keystroke_t*)malloc( sizeof( Keystroke_t ));
	k->ch = ch;
	k->timestamp = timestamp;
	
	mKeystrokes->push_back(k);
	
	if(mKeystrokes->size() > MAX_QUEUE_SIZE)
	{
		//Get references to front-most (earliest) keystroke
		Keystroke_t* oldK = mKeystrokes->front();
		
		//Free that memory
		free(oldK);
		
		//Remove pointer from list
		mKeystrokes->pop_front();
	}
	
	if(!mIsAttacking)
	{
		checkForCombos();
	}
}

void PlayerCharacter::checkForCombos()
{
	//Get the beat objects from the parser
	vector<BeatObject*>* beatObjects = (mGame->getSong())->getBeatObjects(0);
	
	//Create iterator for the keystrokes
	list<Keystroke_t*>::iterator i;
	
	bool isCombo = false;
	mPerformedCommand = NULL;
	
	vector<Command_t*>* commands = mGame->getCommands();
	assert(commands);
	
	//Start off with an empty string
	string keystring = "";
	
	//Add each character of the keystrokes to the string, in order
	for(i = mKeystrokes->begin(); i != mKeystrokes->end(); ++i)
	{
		Keystroke_t* k = *i;
		assert(k);
		keystring.append(1, k->ch);
	}
	
	//Now convert to C-style string so that I can use strstr()
	const char* c_keys = keystring.c_str();
	int keystring_len = strlen(c_keys);
	//Now lets search for the commands in our C-style string
	
	for(int i = 0; i < commands->size(); i++)
	{
		Command_t* command = (*commands)[i];
		int cmd_len = strlen(command->cmd);
		const char* result = strlstr(c_keys, command->cmd);
		if(result != NULL)
		{
			/*
			Okay, so it found the command in our key sequence!
			This is only a positive match though if it found it
			exactly at the END of our c_keys string
			*/
			
			if(result == &(c_keys[keystring_len - cmd_len]) )
			{
				//It's a match!
				mPerformedCommand = command;
				break;
			}
		}
	}
	
	if(mPerformedCommand == NULL)
	{
		//They didn't perform any commands
		return;
	}
	
	//Okay, we know they performed a command, but did they do it on beat
	int cmd_len = strlen(mPerformedCommand->cmd);
	int count = 0;
	
	list<Keystroke_t*>::reverse_iterator rit;
	//int beat_start = 0;
	
	vector<BeatObject*> theBeats;
	for(rit = mKeystrokes->rbegin();  count < cmd_len; rit++)
	{
		Keystroke_t* k = *rit;
		bool onBeat = false;
		float keyTimestamp = (float)( (float) k->timestamp / 1000.0);
		
		if(count == 0)
		{
			//Go sequentially forward to match the latest keystroke...
			for( ; mLastMatchedBeatObject < beatObjects->size(); mLastMatchedBeatObject += BEAT_OBJECT_INTERVAL)
			{
				
				BeatObject* bo = (*beatObjects)[mLastMatchedBeatObject];
				if( ( (bo->m_tatum - BEAT_MATCH_THRESHOLD) < keyTimestamp ) && ( keyTimestamp < (bo->m_tatum + BEAT_MATCH_THRESHOLD) ) )
				{
					//It's on beat!
					onBeat = true;
					theBeats.push_back(bo);
					break;
				}
				else if(bo->m_tatum > keyTimestamp)
				{
					onBeat = false;
					break;
				}
			
			}
		}
		else
		{
			int index = mLastMatchedBeatObject - (BEAT_MATCH_THRESHOLD * count);
			BeatObject* bo = (*beatObjects)[index];
			if( ( (bo->m_tatum - BEAT_MATCH_THRESHOLD) < keyTimestamp ) && ( keyTimestamp < (bo->m_tatum + BEAT_MATCH_THRESHOLD) ) )
			{
				//It's on beat!
				onBeat = true;
				theBeats.push_back(bo);
				break;
			}
			else if(bo->m_tatum > keyTimestamp)
			{
				onBeat = false;
				break;
			}
			
		}		
		if(!onBeat)
		{
			//couldn't find a beat for this guy... sorry no deal
			return;
		}
		count++;
	}
	
	
	mPerformedCommand->statePtr = true;
	mMultiplier = mPerformedCommand->multiplier;
	
	/*
	float thresh = 1.5;
	if( ( (theBeats[theBeats.size() - 1])->m_tatum - (theBeats[0]->m_tatum) ) < thresh)
	{
		//This is a valid combo!
		performedCommand->statePtr = true;
	}
	*/
	
}

void PlayerCharacter::punch()
{
	//
	float damage = 5.0;
	vector<NonPlayerCharacter*>* enemies = mGame->getEnemies();
	
	for(int i = 0; i < enemies->size(); i++)
	{
		//
		NonPlayerCharacter* e = (*enemies)[i];
		if(isInRangeOf(e))
		{
			e->setHealth(e->getHealth() - (damage * mMultiplier));
			//Increase the score
			mGame->addScore( damage * mMultiplier );
		}
	}
	
	
	
	//Now update player state
	assert(mPerformedCommand);
	mIsAttacking = true;
	mTimeUntilIdle = mPerformedCommand->duration;
	
}

void PlayerCharacter::kick()
{
	//
	float damage = 5.0;
	vector<NonPlayerCharacter*>* enemies = mGame->getEnemies();
	
	for(int i = 0; i < enemies->size(); i++)
	{
		//
		NonPlayerCharacter* e = (*enemies)[i];
		if(isInRangeOf(e))
		{
			e->setHealth(e->getHealth() - (damage * mMultiplier));
			//Increase the score by damage * multipler
			mGame->addScore(damage * mMultiplier);
		}
	}
	
	
	
	//Now update player state
	assert(mPerformedCommand);
	mIsAttacking = true;
	mTimeUntilIdle = mPerformedCommand->duration;
}

string PlayerCharacter::getKeyBuffer()
{
	//Create iterator for the keystrokes
	list<Keystroke_t*>::iterator i;
	
	//Start off with an empty string
	string keystring = "";
	
	//Add each character of the keystrokes to the string, in order
	for(i = mKeystrokes->begin(); i != mKeystrokes->end(); ++i)
	{
		Keystroke_t* k = *i;
		assert(k);
		keystring.append(1, k->ch);
	}
	
	return keystring;
}

void PlayerCharacter::clearKeyBuffer()
{
	mKeystrokes->clear();
}

